//! 一个简单的命令行参数解析库
//! 
//! 这个库提供了解析命令行参数的功能，支持以下特性：
//! - 短选项（如 -v）
//! - 长选项（如 --verbose）
//! - 带值的选项（如 --name=value 或 -n value）
//! - 位置参数
//! - 帮助信息生成

use std::collections::HashMap;
use std::env;

/// 表示一个命令行选项的定义
#[derive(Debug, Clone)]
pub struct OptionDef {
    /// 短选项名（单个字符，如 'v'）
    pub short: Option<char>,
    /// 长选项名（如 "verbose"）
    pub long: Option<String>,
    /// 选项描述，用于生成帮助信息
    pub description: String,
    /// 是否需要一个值
    pub takes_value: bool,
}

impl OptionDef {
    /// 创建一个新的选项定义
    pub fn new(short: Option<char>, long: Option<String>, description: &str, takes_value: bool) -> Self {
        OptionDef {
            short,
            long,
            description: description.to_string(),
            takes_value,
        }
    }
}

/// 解析后的命令行参数
#[derive(Debug)]
pub struct Args {
    /// 选项及其值
    options: HashMap<String, Option<String>>,
    /// 位置参数
    positional: Vec<String>,
}

impl Args {
    /// 检查是否存在指定的选项
    pub fn has_option(&self, name: &str) -> bool {
        self.options.contains_key(name)
    }

    /// 获取选项的值，如果选项不存在或没有值则返回None
    pub fn get_option(&self, name: &str) -> Option<&str> {
        self.options.get(name).and_then(|v| v.as_deref())
    }

    /// 获取位置参数
    pub fn get_positional(&self) -> &[String] {
        &self.positional
    }
}

/// 命令行参数解析器
#[derive(Debug)]
pub struct ArgParser {
    /// 程序名称
    program_name: String,
    /// 程序描述
    description: String,
    /// 选项定义
    options: Vec<OptionDef>,
}

impl ArgParser {
    /// 创建一个新的参数解析器
    pub fn new(program_name: &str, description: &str) -> Self {
        ArgParser {
            program_name: program_name.to_string(),
            description: description.to_string(),
            options: Vec::new(),
        }
    }

    /// 添加一个选项定义
    pub fn add_option(&mut self, option: OptionDef) -> &mut Self {
        self.options.push(option);
        self
    }

    /// 解析命令行参数
    pub fn parse(&self) -> Result<Args, String> {
        let args: Vec<String> = env::args().collect();
        self.parse_from(args)
    }

    /// 从给定的参数列表解析
    pub fn parse_from(&self, args: Vec<String>) -> Result<Args, String> {
        let mut options = HashMap::new();
        let mut positional = Vec::new();
        
        let mut i = 1; // 跳过程序名
        while i < args.len() {
            let arg = &args[i];
            
            if arg.starts_with("--") {
                // 长选项
                let mut parts = arg[2..].splitn(2, '=');
                let name = parts.next().unwrap();
                let value_part = parts.next();
                
                let option_def = self.find_option_by_long(name);
                if let Some(def) = option_def {
                    let key = def.long.as_ref().unwrap().clone();
                    
                    if def.takes_value {
                        if let Some(value) = value_part {
                            // --name=value 形式
                            options.insert(key, Some(value.to_string()));
                        } else if i + 1 < args.len() && !args[i + 1].starts_with('-') {
                            // --name value 形式
                            options.insert(key, Some(args[i + 1].clone()));
                            i += 1;
                        } else {
                            return Err(format!("选项 '--{}' 需要一个值", name));
                        }
                    } else {
                        // 不带值的标志
                        options.insert(key, None);
                    }
                } else {
                    return Err(format!("未知选项: '--{}'", name));
                }
            } else if arg.starts_with('-') && arg.len() > 1 {
                // 短选项
                let chars: Vec<char> = arg[1..].chars().collect();
                
                for (j, &c) in chars.iter().enumerate() {
                    let option_def = self.find_option_by_short(c);
                    
                    if let Some(def) = option_def {
                        let key = if let Some(long) = &def.long {
                            long.clone()
                        } else {
                            c.to_string()
                        };
                        
                        if def.takes_value {
                            if j < chars.len() - 1 {
                                // -xvalue 形式，其中x是最后一个选项字符
                                let value: String = chars[j+1..].iter().collect();
                                options.insert(key, Some(value));
                                break;
                            } else if i + 1 < args.len() && !args[i + 1].starts_with('-') {
                                // -x value 形式
                                options.insert(key, Some(args[i + 1].clone()));
                                i += 1;
                                break;
                            } else {
                                return Err(format!("选项 '-{}' 需要一个值", c));
                            }
                        } else {
                            // 不带值的标志
                            options.insert(key, None);
                        }
                    } else {
                        return Err(format!("未知选项: '-{}'", c));
                    }
                }
            } else {
                // 位置参数
                positional.push(arg.clone());
            }
            
            i += 1;
        }
        
        Ok(Args { options, positional })
    }

    /// 生成帮助信息
    pub fn help(&self) -> String {
        let mut help = format!("{} - {}\n\n用法: {} [选项] [参数...]\n\n选项:\n", 
                              self.program_name, self.description, self.program_name);
        
        for opt in &self.options {
            let mut option_text = String::new();
            
            if let Some(short) = opt.short {
                option_text.push_str(&format!("-{}", short));
                if opt.long.is_some() {
                    option_text.push_str(", ");
                }
            }
            
            if let Some(long) = &opt.long {
                option_text.push_str(&format!("--{}", long));
            }
            
            if opt.takes_value {
                option_text.push_str(" <值>");
            }
            
            help.push_str(&format!("  {:<20} {}\n", option_text, opt.description));
        }
        
        help
    }

    // 辅助方法：通过短选项名查找选项定义
    fn find_option_by_short(&self, short: char) -> Option<&OptionDef> {
        self.options.iter().find(|opt| opt.short == Some(short))
    }
    
    // 辅助方法：通过长选项名查找选项定义
    fn find_option_by_long(&self, long: &str) -> Option<&OptionDef> {
        self.options.iter().find(|opt| opt.long.as_ref().map(|l| l == long).unwrap_or(false))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_parsing() {
        let mut parser = ArgParser::new("test", "测试程序");
        parser.add_option(OptionDef::new(Some('v'), Some("verbose".to_string()), "启用详细输出", false));
        parser.add_option(OptionDef::new(Some('n'), Some("name".to_string()), "指定名称", true));
        
        let args = vec![
            "program".to_string(),
            "-v".to_string(),
            "--name=test".to_string(),
            "pos1".to_string(),
            "pos2".to_string(),
        ];
        
        let result = parser.parse_from(args).unwrap();
        
        assert!(result.has_option("verbose"));
        assert_eq!(result.get_option("name"), Some("test"));
        assert_eq!(result.get_positional(), &["pos1", "pos2"]);
    }

    #[test]
    fn test_short_option_with_value() {
        let mut parser = ArgParser::new("test", "测试程序");
        parser.add_option(OptionDef::new(Some('n'), Some("name".to_string()), "指定名称", true));
        
        let args = vec![
            "program".to_string(),
            "-n".to_string(),
            "test".to_string(),
        ];
        
        let result = parser.parse_from(args).unwrap();
        assert_eq!(result.get_option("name"), Some("test"));
    }

    #[test]
    fn test_combined_short_options() {
        let mut parser = ArgParser::new("test", "测试程序");
        parser.add_option(OptionDef::new(Some('a'), Some("alpha".to_string()), "选项A", false));
        parser.add_option(OptionDef::new(Some('b'), Some("beta".to_string()), "选项B", false));
        
        let args = vec![
            "program".to_string(),
            "-ab".to_string(),
        ];
        
        let result = parser.parse_from(args).unwrap();
        assert!(result.has_option("alpha"));
        assert!(result.has_option("beta"));
    }
}